﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AESyouhua
{
    class Decryption
    {
        public static int[,] cipher;
        public static int[,] plian;
        public static int[,] key;
        private static char[] alphabet = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
        public static int[,] Getdecryption(string str, int[,] _key)
        {
            //int[] cipherkey = new int[16];
            char[] ch = str.ToCharArray();
            int[] ch1 = new int[ch.Length];
            key = _key;
             cipher = new int[str.Length / 32, 16];
            plian = new int[str.Length / 32, 16];
           //int[] plaintext = new int[16];

            int m = 0;
            for (int i = 0; i < str.Length; i++)
            {
               ch1[i] = Decryption.GetNum(ch[i]);
            }

            for (int i = 0; i < cipher.GetLength(0); i++)
            {
                for (int j = 0; j < 16; j++)
                {
                    string a = GetZiFu(ch1[m]);
                    string b = GetZiFu(ch1[m + 1]);
                    cipher[i, j] = Convert.ToInt32((a + b), 2);
                    m += 2;
                }
            }

            if (cipher.GetLength(0) >= 4)
            {
                int index = cipher.GetLength(0);
                List<Task> taskList = new List<Task>();// 准备一个task集合
                TaskFactory taskFactory = new TaskFactory();//创建一个task工厂
                //int tasknum = 0;
                for (int i = 0; i < index; i++)
                {
                    int s = i;
                    Action act = () => fenzuState(s);
                    Task task = taskFactory.StartNew(act);//启动线程  开启一个task
                    taskList.Add(task);

                    if (s + 1 < index)
                    {
                        Action act1 = () => fenzuState(s + 1);
                        Task task1 = taskFactory.StartNew(act1);//启动线程  开启一个task
                        taskList.Add(task1);
                        if (s + 2 < index)
                        {
                            Action act2 = () => fenzuState(s + 2);
                            Task task2 = taskFactory.StartNew(act2);//启动线程  开启一个task
                            taskList.Add(task2);
                            if (s + 3 < index)
                            {
                                Action act3 = () => fenzuState(s + 3);
                                Task task3 = taskFactory.StartNew(act3);//启动线程  开启一个task
                                taskList.Add(task3);
                            }
                            else
                            {
                                break;
                            }

                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }

                    if (taskList.Count > 4)
                    {
                        Task.WaitAny(taskList.ToArray());
                        taskList = taskList.Where(t => t.Status == TaskStatus.Running).ToList();
                    }
                }
                Task.WaitAll(taskList.ToArray());
            }
            else
            {
                OneState();
            }

            
            //    int s = i;
            //    Action act = () => fenzuState(s);
            //    Task task = taskFactory.StartNew(act);//启动线程  开启一个task
            //    taskList.Add(task);
            //    tasknum++;
            //    while (tasknum > 15)
            //    {
            //        Task.WaitAny(taskList.ToArray());
            //        tasknum--;
            //    }
            //}
            //Task.WaitAll(taskList.ToArray());
           
            
           
            return plian;
        }

        public static void OneState()
        {
            int[] cipherkey = new int[16];
            int[] plaintext = new int[16];
            for (int i = 0; i < cipher.GetLength(0); i++)
            {
                for (int h = 0; h < 16; h++)
                {
                    cipherkey[h] = key[key.GetLength(0) - 1, h];
                    plaintext[h] = cipher[i, h];
                }
                plaintext = AddRoundKey(plaintext, cipherkey);
                for (int j = key.GetLength(0) - 2; j > 0; j--)
                {
                    for (int h = 0; h < 16; h++)
                    {
                        cipherkey[h] = key[j, h];
                    }
                    for (int h = 0; h < plaintext.Length; h++)
                    {
                        plaintext[h] = SubBytes.GetByteSub(plaintext[h]);
                    }
                    plaintext = InvShiftRows(plaintext);
                    plaintext = MixColumn.InvMixColumn(plaintext);
                    plaintext = AddRoundKey(plaintext, cipherkey);
                }
                for (int h = 0; h < 16; h++)
                {
                    cipherkey[h] = key[0, h];
                }
                for (int h = 0; h < plaintext.Length; h++)
                {
                    plaintext[h] = SubBytes.GetByteSub(plaintext[h]);
                }
                plaintext = InvShiftRows(plaintext);
                plaintext = AddRoundKey(plaintext, cipherkey);
                for (int j = 0; j < 16; j++)
                    plian[i, j] = plaintext[j];
            }
        }

        public static object plus_lock = new object();
        public static void fenzuState(int i)
        {
            int[] plaintext = new int[16];
            int[] cipherkey = new int[16];//秘钥
            for (int h = 0; h < 16; h++)
            {
                cipherkey[h] = key[key.GetLength(0) - 1, h];
                plaintext[h] = cipher[i, h];
            }
            plaintext = AddRoundKey(plaintext, cipherkey);
            for (int j = key.GetLength(0) - 2; j > 0; j--)
            {
                for (int h = 0; h < 16; h++)
                {
                    cipherkey[h] = key[j, h];
                }
                for (int h = 0; h < plaintext.Length; h++)
                {
                    plaintext[h] = SubBytes.GetByteSub(plaintext[h]);
                }
                plaintext = InvShiftRows(plaintext);
                plaintext = MixColumn.InvMixColumn(plaintext);
                plaintext = AddRoundKey(plaintext, cipherkey);
            }
            for (int h = 0; h < 16; h++)
            {
                cipherkey[h] = key[0, h];
            }
            for (int h = 0; h < plaintext.Length; h++)
            {
                plaintext[h] = SubBytes.GetByteSub(plaintext[h]);
            }
            plaintext = InvShiftRows(plaintext);
            plaintext = AddRoundKey(plaintext, cipherkey);
            lock (plus_lock)
            {
                for (int j = 0; j < 16; j++)
                    plian[i, j] = plaintext[j];
            }

        }



        public static int[] AddRoundKey(int[] cipher, int[] key)
        {
            for (int i = 0; i < 16; i++)
            {
                cipher[i] ^= key[i];
            }
            return cipher;
        }
        public static int[] InvShiftRows(int[] cipher)
        {
            int[] cipherX = new int[16];

            for (int i = 0; i < 16; i++)
            {
                if (i % 4 == 0)
                    cipherX[i] = cipher[i];
                if (i % 4 == 1)
                    cipherX[i] = cipher[(i + 12) % 16];
                if (i % 4 == 2)
                    cipherX[i] = cipher[(i + 8) % 16];
                if (i % 4 == 3)
                    cipherX[i] = cipher[(i + 4) % 16];
            }
            return cipherX;
        }
        public static int GetNum(char c)
        {
            int i = 0;
            for (; i < alphabet.Length; i++)
            {
                if (c == alphabet[i])
                {
                    break;
                }
            }
            return i;
        }

        public static string GetZiFu(int c)
        {
            string str = Convert.ToString(c, 2);
            if (str.Length < 4)
            {
                int s = 4 - str.Length;
                for (int i = 0; i < s; i++)
                {
                    str = '0' + str;
                }
            }
            return str;
        }
    }
}
